home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1997 July / macformat52.iso / mac / Shareware Plus / Developers / YAAF v1.0 alpha 1 / (Sources) / Standard Controls / Scrolling / XGScrollView.cpp next >
Encoding:
C/C++ Source or Header  |  1997-04-24  |  12.7 KB  |  618 lines

  1. /*    XGScrollView.cpp
  2.  *
  3.  *        This handles the scrolling view; this is a view which sets
  4.  *    up two scrollbars in the sides and manages scrolling a center view
  5.  */
  6.  
  7. /*  YAAF - Yet another application framework
  8.  *  Copyright (C) 1997 William Edward Woody and In Phase Consulting
  9.  *  
  10.  *  This library is free software; you can redistribute it
  11.  *  and/or modify it under the terms of the GNU Library
  12.  *  General Public License as published by the Free Software
  13.  *  Foundation; either version 2 of the License, or any
  14.  *  later version.
  15.  *  
  16.  *  This library is distributed in the hope that it will be
  17.  *  useful, but WITHOUT ANY WARRANTY; without even the implied
  18.  *  warranty of MERCHANTABIILITY or FITNESS FOR A PARTICULAR
  19.  *  PURPOSE. See the GNU Library General Public License for
  20.  *  more details.
  21.  *  
  22.  *  You should have received a copy of the GNU Library General
  23.  *  Public License along with this library; if not, write to the
  24.  *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  25.  *  Boston, MA 02111-1307, USA.
  26.  *  
  27.  *  To contact the author, either e-mail me at
  28.  *  woody@alumni.caltech.edu, or write to us at
  29.  *  
  30.  *          William Edward Woody
  31.  *          In Phase Consulting
  32.  *          1545 Ard Eevin Avenue
  33.  *          Glendale, CA 91202
  34.  */
  35.  
  36. #include <XError.h>
  37. #include <XStdScrollView.h>
  38.  
  39. /************************************************************************/
  40. /*                                                                        */
  41. /*    Set/Clear Class Object                                                */
  42. /*                                                                        */
  43. /************************************************************************/
  44.  
  45. /*    XGIClear
  46.  *
  47.  *        This class object clears the specified boolean value when
  48.  *    it is created, and sets it when it is exited. This is used
  49.  *    whenever I want to clear the fBounce flag temporarly; it 
  50.  *    guarentees that the flag is set back, even when an error is thrown.
  51.  */
  52.  
  53. class XGIClear {
  54.     public:
  55.         XGIClear(bool &a)    { fA = &a; a = false; }
  56.         ~XGIClear()            { *fA = true; }
  57.     private:
  58.         bool                *fA;
  59. };
  60.  
  61. /************************************************************************/
  62. /*                                                                        */
  63. /*    Construction/Destruction                                            */
  64. /*                                                                        */
  65. /************************************************************************/
  66.  
  67. /*    XGScrollView::XGScrollView
  68.  *
  69.  *        Construct this thing
  70.  */
  71.  
  72. XGScrollView::XGScrollView(XGView *parent, XGArgStream &stream) :
  73.     XGView(parent,stream)
  74. {
  75.     bool h;
  76.     bool v;
  77.     bool c;
  78.     short s;
  79.     
  80.     h = stream.GetBoolean();
  81.     v = stream.GetBoolean();
  82.     c = stream.GetBoolean();
  83.     s = stream.GetInteger();
  84.     
  85.     Init(h,v,c,s);
  86. }
  87.  
  88. XGScrollView::XGScrollView(XGView *parent, XGSScrollViewInitRecord &i) :
  89.     XGView(parent,i.v)
  90. {
  91.     Init(i.hscroll,i.vscroll,i.corner,i.viewID);
  92. }
  93.  
  94. /*    XGScrollView::~XGScrollView
  95.  *
  96.  *        Destruction. Do nothing, as the view deconstructor will
  97.  *    automatically fry my two scrollbars for me
  98.  */
  99.  
  100. XGScrollView::~XGScrollView()
  101. {
  102.     fHScroll = NULL;
  103.     fVScroll = NULL;
  104. }
  105.  
  106. /************************************************************************/
  107. /*                                                                        */
  108. /*    Display management                                                    */
  109. /*                                                                        */
  110. /************************************************************************/
  111.  
  112. /*    XGScrollView::DoDrawView
  113.  *
  114.  *        Handle drawing the corner if it's called for. On the Macintosh
  115.  *    I simply erase the corner to the background color--on Windows, to
  116.  *    a light gray.
  117.  */
  118.  
  119. void XGScrollView::DoDrawView(Rect)
  120. {
  121.     Rect r;
  122.     
  123.     if (fCorner) {
  124.         XGDraw draw(this);
  125.         
  126.         r = CalcCorner();
  127.  
  128. #if OPT_MACOS == 1
  129.         ::EraseRect(&r);
  130. #endif
  131.  
  132. #if OPT_WINOS == 1
  133.         ::FillRect(draw.GetDC(),&r,GetStockObject(LTGRAY_BRUSH));
  134. #endif
  135.     }
  136. }
  137.  
  138. /*    XGScrollView::DoSizeView
  139.  *
  140.  *        Resize this view. This routine resizes everything using
  141.  *    AutoLocate, but inside the scroll rectangle. The exceptions are
  142.  *    the two scrollbars
  143.  */
  144.  
  145. void XGScrollView::DoSizeView()
  146. {
  147.     XGView *view;
  148.     
  149.     for (view = GetChild(); view != NULL; view = view->GetSibling()) {
  150.         if (view == fHScroll) view->SetLocation(CalcHScroll());
  151.         else if (view == fVScroll) view->SetLocation(CalcVScroll());
  152.         else view->AutoLocate(CalcScroll());
  153.     }
  154. }
  155.  
  156. /************************************************************************/
  157. /*                                                                        */
  158. /*    Scroll Management                                                    */
  159. /*                                                                        */
  160. /************************************************************************/
  161.  
  162. /*    XGScrollView::GetScrollValue
  163.  *
  164.  *        Get the current scroll view location
  165.  */
  166.  
  167. void XGScrollView::GetScrollValue(short *x, short *y)
  168. {
  169.     if (fHScroll) *x = fHScroll->GetValue();
  170.     else *x = 0;
  171.     if (fVScroll) *y = fVScroll->GetValue();
  172.     else *y = 0;
  173. }
  174.  
  175. /*    XGScrollView::SetScrollValue
  176.  *
  177.  *        Set the scroll bar location to the new value. This is done
  178.  *    in this complex way in order to guarentee that I scroll both
  179.  *    axis at the same time.
  180.  */
  181.  
  182. void XGScrollView::SetScrollValue(short x, short y)
  183. {
  184.     XGIClear clear(fBounce);                // Clear bounce flag for me
  185.     short ox,oy;
  186.     
  187.     /*
  188.      *    Get the old value
  189.      */
  190.     
  191.     GetScrollValue(&ox,&oy);
  192.     
  193.     /*
  194.      *    Set and get the new value
  195.      */
  196.     
  197.     if (fHScroll) fHScroll->SetValue(x);
  198.     else if (x != 0) {
  199.         XPostError("Horizontal scroll bar not present");
  200.     }
  201.     if (fVScroll) fVScroll->SetValue(y);
  202.     else if (y != 0) {
  203.         XPostError("Vertical scroll bar not present");
  204.     }
  205.     
  206.     GetScrollValue(&x,&y);
  207.     
  208.     /*
  209.      *    Scroll the view if needed
  210.      */
  211.     
  212.     if ((x != ox) && (y != oy)) {
  213.         UpdateChildView();
  214.         ScrollChildView(ox,oy);
  215.     }
  216. }
  217.  
  218. /*    XGScrollView::GetScrollMax
  219.  *
  220.  *        Get the maximum value to scroll
  221.  */
  222.  
  223. void XGScrollView::GetScrollMax(short *x, short *y)
  224. {
  225.     if (fHScroll) *x = fHScroll->GetMaxValue();
  226.     else *x = 0;
  227.     if (fVScroll) *y = fVScroll->GetMaxValue();
  228.     else *y = 0;
  229. }
  230.  
  231. /*    XGScrollView::SetScrollMax
  232.  *
  233.  *        Set the scroll bar location to the new value. This is done
  234.  *    in this complex way in order to guarentee that I scroll both
  235.  *    axis at the same time.
  236.  */
  237.  
  238. void XGScrollView::SetScrollMax(short x, short y)
  239. {
  240.     XGIClear clear(fBounce);                // Clear bounce flag for me
  241.     short ox,oy;
  242.     
  243.     /*
  244.      *    Get the old value
  245.      */
  246.     
  247.     GetScrollValue(&ox,&oy);
  248.     
  249.     /*
  250.      *    Set and get the new value
  251.      */
  252.     
  253.     if (fHScroll) fHScroll->SetMaxValue(x);
  254.     else if (x != 0) {
  255.         XPostError("Horizontal scroll bar not present");
  256.     }
  257.     if (fVScroll) fVScroll->SetMaxValue(y);
  258.     else if (y != 0) {
  259.         XPostError("Vertical scroll bar not present");
  260.     }
  261.     
  262.     GetScrollValue(&x,&y);
  263.     
  264.     /*
  265.      *    Scroll the view if needed
  266.      */
  267.     
  268.     if ((x != ox) && (y != oy)) {
  269.         UpdateChildView();
  270.         ScrollChildView(ox,oy);
  271.     }
  272. }
  273.  
  274. /*    XGScrollView::GetScrollPage
  275.  *
  276.  *        Get the page size amount for this thing
  277.  */
  278.  
  279. void XGScrollView::GetScrollPage(short *x, short *y)
  280. {
  281.     if (fHScroll) *x = fHScroll->GetPageValue();
  282.     else *x = 0;
  283.     if (fVScroll) *y = fVScroll->GetPageValue();
  284.     else *y = 0;
  285. }
  286.  
  287. /*    XGScrollView::SetScrollPage
  288.  *
  289.  *        Set the page size for this thing
  290.  */
  291.  
  292. void XGScrollView::SetScrollPage(short x, short y)
  293. {
  294.     if (fHScroll) fHScroll->SetPageValue(x);
  295.     else if (x != 0) {
  296.         XPostError("Horizontal scroll bar not present");
  297.     }
  298.     if (fVScroll) fVScroll->SetPageValue(y);
  299.     else if (y != 0) {
  300.         XPostError("Vertical scroll bar not present");
  301.     }
  302. }
  303.  
  304.  
  305. /************************************************************************/
  306. /*                                                                        */
  307. /*    Message dispatch                                                    */
  308. /*                                                                        */
  309. /************************************************************************/
  310.  
  311. /*    XGScrollView::ReceiveDispatch
  312.  *
  313.  *        This sends the scrollbar control messages to my children
  314.  *    views.
  315.  */
  316.  
  317. long XGScrollView::ReceiveDispatch(long msg, long arg, void *parg)
  318. {
  319.     XGSScrollEvent *e;
  320.     
  321.     if (fBounce) switch (msg) {
  322.         case KEventPreScroll:
  323.             /*
  324.              *    The scrollbar is about to scroll. Force update of the
  325.              *    bits in my child view
  326.              */
  327.             
  328.             UpdateChildView();
  329.             return 0;
  330.         case KEventScroll:
  331.             /*
  332.              *    The scrollbar is scrolling. Scroll the bits
  333.              */
  334.             
  335.             e = (XGSScrollEvent *)parg;
  336.             if (e->scroll == fHScroll) ScrollChildView(e->oldvalue,0);
  337.             else if (e->scroll == fVScroll) ScrollChildView(0,e->oldvalue);
  338.             else return XGView::ReceiveDispatch(msg,arg,parg);
  339.             return 0;
  340.         default:
  341.             break;
  342.     }
  343.     
  344.     return XGView::ReceiveDispatch(msg,arg,parg);
  345. }
  346.  
  347. /************************************************************************/
  348. /*                                                                        */
  349. /*    Initialization support                                                */
  350. /*                                                                        */
  351. /************************************************************************/
  352.  
  353. /*    XGScrollView::Init
  354.  *
  355.  *        Common initilization
  356.  */
  357.  
  358. void XGScrollView::Init(bool h, bool v, bool c, short s)
  359. {
  360.     XGSScrollInitRecord si;
  361.     Rect r;
  362.     
  363.     /*
  364.      *    Bit sanity check
  365.      */
  366.     
  367.     if (!h && !v) {
  368.         throw XPostError("Must have at least one scrollbar in a scroll view");
  369.     }
  370.     if (h && v) c = true;            /* Override corner bit */
  371.     
  372.     /*
  373.      *    Initialize random fields
  374.      */
  375.     
  376.     fChildID = s;
  377.     fCorner = c;
  378.     fDelta = 12;                    /* Random stupid value */
  379.     fHScroll = NULL;
  380.     fVScroll = NULL;
  381.     fBounce = true;
  382.     
  383.     /*
  384.      *    Time to initialize my scrollbars
  385.      */
  386.     
  387.     if (h) {
  388.         r = CalcHScroll();
  389.         
  390.         si.v.fViewType = 'scrl';        /* Scroll bar */
  391.         si.v.fViewID = -1;                /* Ignored ID */
  392.         si.v.fRefNum = 0;                /* RefCon value ignored */
  393.         
  394.         si.v.fLockLeft = false;            /* Ignored values */
  395.         si.v.fLockLeft = false;
  396.         si.v.fLockLeft = false;
  397.         si.v.fLockLeft = false;
  398.         
  399.         si.v.fAutoLeft   = r.left;        /* Where do I go? */
  400.         si.v.fAutoRight  = r.right;
  401.         si.v.fAutoTop    = r.top;
  402.         si.v.fAutoBottom = r.bottom;
  403.         
  404.         si.v.fVisible = true;
  405.         si.v.fEnabled = true;
  406.         si.v.fTabStop = false;
  407.         
  408.         si.page = 0;                    /* Random stupid value */
  409.         si.min = 0;
  410.         si.max = 0;
  411.         si.val = 0;
  412.         
  413.         fHScroll = new XGStdScroll(this,si);
  414.     }
  415.     
  416.     if (v) {
  417.         r = CalcVScroll();
  418.         
  419.         si.v.fViewType = 'scrl';        /* Scroll bar */
  420.         si.v.fViewID = -1;                /* Ignored ID */
  421.         si.v.fRefNum = 0;                /* RefCon value ignored */
  422.         
  423.         si.v.fLockLeft = false;            /* Ignored values */
  424.         si.v.fLockLeft = false;
  425.         si.v.fLockLeft = false;
  426.         si.v.fLockLeft = false;
  427.         
  428.         si.v.fAutoLeft   = r.left;        /* Where do I go? */
  429.         si.v.fAutoRight  = r.right;
  430.         si.v.fAutoTop    = r.top;
  431.         si.v.fAutoBottom = r.bottom;
  432.         
  433.         si.v.fVisible = true;
  434.         si.v.fEnabled = true;
  435.         si.v.fTabStop = false;
  436.         
  437.         si.page = 0;                    /* Random stupid value */
  438.         si.min = 0;
  439.         si.max = 0;
  440.         si.val = 0;
  441.         
  442.         fVScroll = new XGStdScroll(this,si);
  443.     }
  444. }
  445.  
  446.  
  447. /************************************************************************/
  448. /*                                                                        */
  449. /*    Dimension calculation                                                */
  450. /*                                                                        */
  451. /************************************************************************/
  452.  
  453. /*    XGScrollView::CalcHScroll
  454.  *
  455.  *        Calculate the location of the horizontal scroll bar
  456.  */
  457.  
  458. Rect XGScrollView::CalcHScroll()
  459. {
  460.     Rect r;
  461.     
  462.     r = GetContentRect();
  463.  
  464. #if OPT_MACOS == 1
  465.     r.bottom++;
  466.     r.top = r.bottom - 16;
  467.     r.left--;
  468.     if (fCorner) {
  469.         r.right -= 14;
  470.     } else {
  471.         r.right++;
  472.     }
  473. #endif
  474.  
  475. #if OPT_WINOS == 1
  476.     r.top = r.bottom - ::GetSystemMetrics(SM_CYHSCROLL);
  477.     if (fCorner) {
  478.         r.right -= ::GetSystemMetrics(SM_CXVSCROLL);
  479.     }
  480. #endif
  481.  
  482.     return r;
  483. }
  484.  
  485. /*    XGScrollView::CalcVScroll
  486.  *
  487.  *        Calculate the vertical scroll bar location
  488.  */
  489.  
  490. Rect XGScrollView::CalcVScroll()
  491. {
  492.     Rect r;
  493.     
  494.     r = GetContentRect();
  495.  
  496. #if OPT_MACOS == 1
  497.     r.right++;
  498.     r.left = r.right - 16;
  499.     r.top--;
  500.     if (fCorner) {
  501.         r.bottom -= 14;
  502.     } else {
  503.         r.bottom++;
  504.     }
  505. #endif
  506.  
  507. #if OPT_WINOS == 1
  508.     r.left = r.right - ::GetSystemMetrics(SM_CYHSCROLL);
  509.     if (fCorner) {
  510.         r.bottom -= ::GetSystemMetrics(SM_CXVSCROLL);
  511.     }
  512. #endif
  513.  
  514.     return r;
  515. }
  516.  
  517. /*    XGScrollView::CalcCorner
  518.  *
  519.  *        Calculate the corner size
  520.  */
  521.  
  522. Rect XGScrollView::CalcCorner()
  523. {
  524.     Rect r;
  525.     
  526.     r = GetContentRect();
  527.  
  528. #if OPT_MACOS == 1
  529.     r.top = r.bottom - 14;
  530.     r.left = r.right - 14;
  531. #endif
  532.  
  533. #if OPT_WINOS == 1
  534.     r.top = r.bottom - ::GetSystemMetrics(SM_CYHSCROLL);
  535.     r.left = r.right - ::GetSystemMetrics(SM_CYHSCROLL);
  536. #endif
  537.  
  538.     return r;
  539. }
  540.  
  541. /*    XGScrollView::CalcScroll
  542.  *
  543.  *        Calculate the scrollbar area
  544.  */
  545.  
  546. Rect XGScrollView::CalcScroll()
  547. {
  548.     Rect r;
  549.     
  550.     r = GetContentRect();
  551.  
  552. #if OPT_MACOS == 1
  553.     if (fHScroll) r.bottom = r.bottom - 15;
  554.     if (fVScroll) r.right = r.right - 15;
  555. #endif
  556.  
  557. #if OPT_WINOS == 1
  558.     if (fHScroll) r.bottom = r.bottom - ::GetSystemMetrics(SM_CYHSCROLL);
  559.     if (fVScroll) r.right = r.right - ::GetSystemMetrics(SM_CYHSCROLL);
  560. #endif
  561.  
  562.     return r;
  563. }
  564.  
  565. /************************************************************************/
  566. /*                                                                        */
  567. /*    Child view support                                                    */
  568. /*                                                                        */
  569. /************************************************************************/
  570.  
  571. /*    XGScrollView::InvalChildView
  572.  *
  573.  *        Invalidate child view
  574.  */
  575.  
  576. void XGScrollView::InvalChildView()
  577. {
  578.     XGView *v;
  579.     
  580.     v = FindViewByID(fChildID);
  581.     if (v) v->InvalView();
  582. }
  583.  
  584. /*    XGScrollView::UpdateChildView
  585.  *
  586.  *        Update child view
  587.  */
  588.  
  589. void XGScrollView::UpdateChildView()
  590. {
  591.     XGView *v;
  592.     
  593.     v = FindViewByID(fChildID);
  594.     if (v) v->UpdateView();
  595. }
  596.  
  597. /*    XGScrollView::ScrollChildView
  598.  *
  599.  *        Scroll the child view
  600.  */
  601.  
  602. void XGScrollView::ScrollChildView(short ox, short oy)
  603. {
  604.     short nx,ny;
  605.     long dx,dy;
  606.     XGView *v;
  607.     
  608.     v = FindViewByID(fChildID);
  609.     if (!v) return;
  610.     
  611.     /* Calculate scroll amount */
  612.     GetScrollValue(&nx,&ny);
  613.     dx = (long)(ox - nx) * fDelta;
  614.     dy = (long)(oy - ny) * fDelta;
  615.     v->Scroll(dx,dy);
  616.     v->UpdateView();
  617. }
  618.